package edu.xlh.travel.service.impl;

import edu.xlh.travel.common.Result;
import edu.xlh.travel.dao.ValidateDao;
import edu.xlh.travel.pojo.User;
import edu.xlh.travel.pojo.Validate;
import edu.xlh.travel.service.UserService;
import edu.xlh.travel.service.ValidateService;


import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
@Transactional
public class ValidateServiceImpl implements ValidateService {
    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private  ValidateDao validateDao;

    @Autowired
    private UserService userService;

    //发送邮件的类
    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private BCryptPasswordEncoder encoder;

    //这里使用的是我们已经在配置问价中固定了的变量值,也就是通过这个邮箱向目标邮箱发送重置密码的邮件
    @Value("${spring.mail.username}")
    private String from;

    @Async
    public void sendPasswordResetEmail(MimeMessage email) {
        javaMailSender.send(email);
    }


    public int insertNewResetRecord(Validate validate, User user, String token) {
        validate.setUserId(user.getId());
        validate.setEmail(user.getEmail());
        validate.setResetToken(token);
        validate.setType("passwordReset");
        validate.setGmtCreate(new Date());
        validate.setGmtModified(new Date());
        return validateDao.insert(validate);
    }


    public Validate findUserByResetToken(String token) {
        return validateDao.selectByToken(token);
    }


    public boolean sendValidateLimitation(String email, long requestPerDay, long interval) {
        List<Validate> validateDaoList = validateDao.selectByEmail(email);
        // 若查无记录，意味着第一次申请，直接放行
        if (validateDaoList.isEmpty()) {
            return true;
        }
        // 有记录，则判定是否频繁申请以及是否达到日均请求上线
        long countTodayValidation = validateDaoList.stream().filter(x-> DateUtils.isSameDay(x.getGmtModified(), new Date())).count();
        Optional validate = validateDaoList.stream().map(Validate::getGmtModified).max(Date::compareTo);
        Date dateOfLastRequest = new Date();
        if (validate.isPresent()) dateOfLastRequest = (Date) validate.get();
        long intervalForLastRequest = new Date().getTime() - dateOfLastRequest.getTime();

        return countTodayValidation <= requestPerDay && intervalForLastRequest >= interval * 60 * 1000;
    }


    public boolean validateLimitation(String email, long requestPerDay, long interval, String token) {
        List<Validate> validateDaoList = validateDao.selectByEmail(email);
        // 有记录才会调用该函数，只需判断是否超时
        Optional validate = validateDaoList.stream().map(Validate::getGmtModified).max(Date::compareTo);
        Date dateOfLastRequest = new Date();
        if (validate.isPresent()) dateOfLastRequest = (Date) validate.get();
        long intervalForLastRequest = new Date().getTime() - dateOfLastRequest.getTime();

        Optional lastRequestToken = validateDaoList.stream().filter(x-> x.getResetToken().equals(token)).map(Validate::getGmtModified).findAny();
        Date dateOfLastRequestToken = new Date();
        if (lastRequestToken.isPresent()) {
            dateOfLastRequestToken = (Date) lastRequestToken.get();
        }
        return intervalForLastRequest <= interval * 60 * 1000 && dateOfLastRequest == dateOfLastRequestToken;
    }

    @Override
    public Result sendValidationEmail(String email, HttpServletRequest request) throws MessagingException {
        Result restResult=new Result();
        User user = (User)userService.findByEmail(email).getData();
        if (user == null){
            restResult.setCode(201);
            restResult.setMsg("该邮箱所属用户不存在");
        }else {
            if (sendValidateLimitation(email, 20,1)){
                // 若允许重置密码，则在pm_validate表中插入一行数据，带有token
                Validate validate = new Validate();
                insertNewResetRecord(validate, user, UUID.randomUUID().toString());
                // 设置邮件内容
                String appUrl = request.getScheme() + "://" + request.getServerName()+":"+request.getServerPort();
                MimeMessage mimeMessage = mailSender.createMimeMessage();
                // multipart模式
                MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
                mimeMessageHelper.setTo(email);
                mimeMessageHelper.setFrom(from);
                mimeMessageHelper.setSubject("重置密码");
                StringBuilder sb = new StringBuilder();
                sb.append("<html><head></head>");
                sb.append("<body><h1>点击下面的链接重置密码</h1>" +
                        "<a href = "+appUrl +"/dist/forget?token="+validate.getResetToken()+">"+appUrl +"/dist/forget?token=" +validate.getResetToken()+"</a></body>");
                sb.append("</html>");
                // 启用html
                mimeMessageHelper.setText(sb.toString(), true);
                sendPasswordResetEmail(mimeMessage);

//                SimpleMailMessage passwordResetEmail = new SimpleMailMessage();
//                passwordResetEmail.setFrom(from);
//                passwordResetEmail.setTo(email);
//                passwordResetEmail.setSubject("忘记密码");
//                passwordResetEmail.setText("您正在申请重置密码，请点击此链接重置密码: \n" +appUrl + "/validate/resetPassword?token=" + validateDao.getResetToken());
//                validateService.sendPasswordResetEmail(passwordResetEmail);

                Map<String,Object> map1=new HashMap<>();
                map1.put("token",validate.getResetToken());
                map1.put("link",appUrl +"/validate/resetPassword?token="+validate.getResetToken());
                map1.put("message","邮件已经发送");
                restResult.setCode(200);
                restResult.setData(map1);
            }else {
                restResult.setCode(202);
                restResult.setMsg("操作过于频繁，请稍后再试！");
            }
        }
        return restResult;
    }

    @Override
    public Result resetPassword(String token, String password, String confirmPassword) {
        Result restResult=new Result();
        // 通过token找到validate记录
        Validate validate= findUserByResetToken(token);
        User user = userService.findById(validate.getUserId()).get();
        if (validate == null){
            restResult.setCode(201);
            restResult.setMsg("该重置请求不存在");
        }else {
            if (validateLimitation(validate.getEmail(), Long.MAX_VALUE, 5, token)){
                if (password.equals(confirmPassword)) {
                    String salt = UUID.randomUUID().toString();
                    user.setSalt(salt);
                    user.setPassword(encoder.encode(password+salt));
                    userService.updateByPrimaryKeySelective(user);
                    restResult.setCode(200);
                    restResult.setMsg("成功重置密码");
                }else {
                    restResult.setCode(202);
                    restResult.setMsg("确认密码和密码不一致，请重新输入");
                }
            }else {
                restResult.setCode(203);
                restResult.setMsg("该链接失效");
            }
        }
        return restResult;
    }
}
